package com.dfiov.cloud.msmtools.service.business.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.StopWatch;
import cn.hutool.core.lang.Console;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.dfiov.cloud.msmtools.contant.Constants;
import com.dfiov.cloud.msmtools.entity.dto.*;
import com.dfiov.cloud.msmtools.entity.vo.balance.*;
import com.dfiov.cloud.msmtools.entity.vo.msVehiclestatus.VhlDataV2Vo;
import com.dfiov.cloud.msmtools.entity.vo.msbluetooth.SoMobileDeviceNo;
import com.dfiov.cloud.msmtools.entity.vo.msdms.MsRemoteRelationVo;
import com.dfiov.cloud.msmtools.entity.vo.msmtools.*;
import com.dfiov.cloud.msmtools.entity.vo.tspReport.AddDataByMonthAndVersionVo;
import com.dfiov.cloud.msmtools.entity.vo.tspReport.BaseAccountStaticExcelVo;
import com.dfiov.cloud.msmtools.entity.vo.tspReport.ExportDataByMonthAndVersionVo;
import com.dfiov.cloud.msmtools.enums.*;
import com.dfiov.cloud.msmtools.mapper.entity.msdevice.MsCreditBusinessVehicle;
import com.dfiov.cloud.msmtools.mapper.entity.msaccount.UserProfileListItemVo;
import com.dfiov.cloud.msmtools.mapper.entity.msbluetooth.*;
import com.dfiov.cloud.msmtools.mapper.entity.msdevice.*;
import com.dfiov.cloud.msmtools.mapper.entity.msinfofeedback.NewFeedbackPageVo;
import com.dfiov.cloud.msmtools.mapper.entity.msinfofeedback.NewFeedbackRecord;
import com.dfiov.cloud.msmtools.mapper.entity.msinfofeedback.PageResult;
import com.dfiov.cloud.msmtools.mapper.entity.msinfofeedback.ResultData;
import com.dfiov.cloud.msmtools.mapper.entity.msmtools.*;
import com.dfiov.cloud.msmtools.mapper.entity.msmtools.MsmtoolsColumnsDo;
import com.dfiov.cloud.msmtools.mapper.msdevice.MsDeviceMapper;
import com.dfiov.cloud.msmtools.mapper.msmtoolsMapper.AuthMapper;
import com.dfiov.cloud.msmtools.mapper.tspreport.TspReportMapper;
import com.dfiov.cloud.msmtools.service.business.AuthService;
import com.dfiov.cloud.msmtools.service.feign.*;
import com.dfiov.cloud.msmtools.utils.ExcelUtils;
import com.dfiov.cloud.msmtools.utils.ResponseUtils;
import com.dfiov.cloud.msmtools.utils.JasperUtils;
import com.pateo.qingcloud.framework.common.base.BaseRestResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import java.util.stream.Collectors;


@Slf4j
@Service
public class AuthImpl implements AuthService {

    @Resource
    AuthMapper authMapper;

    @Autowired
    private MsunicomFeign msunicomFeign;

    @Autowired
    MsDeviceFeignClient msDeviceFeignClient;

    @Autowired
    MsdmsFeign msdmsFeign;

    @Autowired
    MsAccountFeignClient msAccountFeignClient;

    @Autowired
    MsIBlueToothKeyFeignClient msIBlueToothKeyFeignClient;

    @Autowired
    MsSoIBlueToothKeyFeignClient msSoIBlueToothKeyFeignClient;

    @Autowired
    MsvehiclestatusFeign msvehiclestatusFeign;

    @Autowired
    MsinfofeedbackFeginClient msinfofeedbackFeginClient;

    @Resource
    MsDeviceMapper msDeviceMapper;

    @Resource
    TspReportMapper tspReportMapper;

    private final String[] carName_old_dfpvivi = {"AX7(PRO)","C68","G35","C65","E70","M57","G59","D53 EV","d53","D53","X37b","D58"};
    private final String[] carName_new_dfpvivi = {"P57","S01","S01-F"};
    private final String[] carName_dnaivi = {"S31"};
    private final String[] carName_dfpv2ivi = {"S73","S59"};
    static String vehicle_log ="vehicle_log";
    static String vehicle_statistics ="vehicle_statistics";


    @Override
    public BaseRestResponse<MsmtoolsUserInfoDto> getUserByUserId(int userId) {
        log.info("getUserByUserId::" + userId);
        MsmtoolsUserInfoDo msmtoolsUserInfoDo = authMapper.selectOneMsmtoolsUserInfo(userId);
        log.info("msmtoolsUserInfo::" + JSON.toJSONString(msmtoolsUserInfoDo));
        MsmtoolsUserInfoDto msmtoolsUserInfoDto = new MsmtoolsUserInfoDto();
        BeanUtils.copyProperties(msmtoolsUserInfoDo, msmtoolsUserInfoDto);
        return ResponseUtils.success(msmtoolsUserInfoDto);
    }

    @Override
    public List<MsmtoolsUserInfoDto> selectAllMsmtoolsUserInfo(int page,int pagesize) {
        return authMapper.selectAllMsmtoolsUserInfo((page - 1) * pagesize, pagesize);
    }

    @Override
    public List<MsmtoolsMessageDo> selectAllMsmtoolsMessage(int page, int pagesize, String name, String description) {
        return authMapper.selectAllMsmtoolsMessage(name,description,(page - 1) * pagesize, pagesize);
    }

    @Override
    public List<MsmtoolsPowerDo> selectAllMsmtoolsPower() {
        return authMapper.selectAllCountMsmtoolsPower();
    }

    @Override
    public int selectAllCountMsmtoolsUserInfo() {
        return authMapper.selectAllCountMsmtoolsUserInfo();
    }

    @Override
    public int selectAllCountMsmtoolsMessage() {
        return authMapper.selectAllCountMsmtoolsMessage();
    }

    @Override
    public MsmtoolsUserInfoDo getUserByAccountAndPswd(String account, String pswd) {
        log.info("getUserByAccountAndPswd::" + account + ",pswd::" + pswd);
        MsmtoolsUserInfoDo msmtoolsUserInfoDo = authMapper.getUserByAccountAndPswd(account, pswd);
        log.info("msmtoolsUserInfo::" + JSON.toJSONString(msmtoolsUserInfoDo));
        return msmtoolsUserInfoDo;
    }

    @Override
    public UserTokensDo getUserTokensByUserId(int userId) {
        return authMapper.selectUserTokensByUserId(userId);
    }

    @Override
    public int saveUserTokens(UserTokensDo userTokensDo) {
        return authMapper.saveUserTokens(userTokensDo);
    }

    @Override
    public int saveMsmtoolsUserInfoDo(MsmtoolsUserInfoDo msmtoolsUserInfoDo) {
        String pswd = getPswd(msmtoolsUserInfoDo.getAccount(),msmtoolsUserInfoDo.getPswd());
        msmtoolsUserInfoDo.setPswd(pswd);
        msmtoolsUserInfoDo.setDelFlag(0);
        msmtoolsUserInfoDo.setTypeId(1);
        return authMapper.saveMsmtoolsUserInfoDo(msmtoolsUserInfoDo);
    }

    @Override
    public String adduserinfo(MsmtoolsUserInfoVo msmtoolsUserInfoVo) {

        MsmtoolsUserInfoDo msmtoolsUserInfoDo = new MsmtoolsUserInfoDo();
        msmtoolsUserInfoDo.setTypeId(msmtoolsUserInfoVo.getType_id());
        msmtoolsUserInfoDo.setPswd(getPswd(msmtoolsUserInfoVo.getAccount(),msmtoolsUserInfoVo.getPswd()));
        msmtoolsUserInfoDo.setAccount(msmtoolsUserInfoVo.getAccount());
        msmtoolsUserInfoDo.setUserName(msmtoolsUserInfoVo.getUsername());
        msmtoolsUserInfoDo.setDelFlag(0);

        MsmtoolsUserInfoDo msmtoolsUserInfoDoOld = authMapper.getUserByAccount(msmtoolsUserInfoVo.getAccount());
        if(Objects.nonNull(msmtoolsUserInfoDoOld)){
            msmtoolsUserInfoDo.setUserId(msmtoolsUserInfoDoOld.getUserId());
            int count = authMapper.updateMsmtoolsUserInfoDo(msmtoolsUserInfoDo);
            return count>0?"添加成功":"失败";
        }
        int count = authMapper.saveMsmtoolsUserInfoDo(msmtoolsUserInfoDo);
        return count>0?"添加成功":"失败";
    }

    @Override
    public List<MsmtoolsMenuDto> selectMenu(int userId) {
        log.info("selectMenu::" + userId);
        String menus = authMapper.selectMenuByUserId(userId);
        log.info("selectMenu::" + JSON.toJSONString(menus));

        List<Integer> mIds = Arrays.stream(menus.split(",")).map(Integer::parseInt).collect(Collectors.toList());
        log.info("mIds::" + JSON.toJSONString(mIds));
        List<MsmtoolsMenuDo> msmtoolsMenuDos = authMapper.selectMsmtoolsMenuListByMIds(mIds);

        ArrayList<MsmtoolsMenuDto> msmtoolsMenuDtoList = new ArrayList<>();
        msmtoolsMenuDos.forEach(msmtoolsMenuDo -> msmtoolsMenuDtoList.add(copyMsmtoolsDto(msmtoolsMenuDo)));
        log.info("msmtoolsMenuDtoList::" + JSON.toJSONString(msmtoolsMenuDtoList));
        return msmtoolsMenuDtoList;
    }

    @Override
    public MsmtoolsMenuDto getMenuInfoByMId(String key) {
        return copyMsmtoolsDto(authMapper.selectOneMsmtoolsMenuByMId(Integer.parseInt(key)));
    }

    @Override
    public List<MsmtoolsColumnsDo> getmenulist(String tableName) {
        return authMapper.getmenulist(tableName);
    }

    @Override
    public List<MsmtoolsMenuAndChildrenDto> getMenuAllandChildren() {
        List<MsmtoolsMenuDo> msmtoolsMenuDoList = authMapper.selectAllMsmtoolsMenu();

        HashMap<Integer, MsmtoolsMenuAndChildrenDto> map = new HashMap<>();
        msmtoolsMenuDoList.stream()
                .sorted(Comparator.comparingInt(MsmtoolsMenuDo::getParentMId))
                .sorted(Comparator.comparingInt(MsmtoolsMenuDo::getMId))
                .forEach(msmtoolsMenuDo -> {
                    MsmtoolsMenuAndChildrenDto msmtoolsMenuAndChildrenDto = copyMsmtoolsMenuAndChildrenDto(msmtoolsMenuDo);
                    if (msmtoolsMenuDo.getParentMId() == 0) {
                        List<MsmtoolsMenuDto> list = new ArrayList<>();
                        msmtoolsMenuAndChildrenDto.setChildren(list);
                        map.put(msmtoolsMenuDo.getMId(),msmtoolsMenuAndChildrenDto);
                    } else {
                        MsmtoolsMenuAndChildrenDto msmtoolsMenuParent = map.get(msmtoolsMenuDo.getParentMId());
                        List<MsmtoolsMenuDto> childrenList = msmtoolsMenuParent.getChildren();
                        childrenList.add(msmtoolsMenuAndChildrenDto);
                        msmtoolsMenuParent.setChildren(childrenList);
                    }
                });

        ArrayList<MsmtoolsMenuAndChildrenDto> msmtoolsMenuAndChildrenList = new ArrayList<>();
        map.forEach((integer, msmtoolsMenuAndChildrenDto) -> msmtoolsMenuAndChildrenList.add(msmtoolsMenuAndChildrenDto));
        return msmtoolsMenuAndChildrenList;
    }

    @Override
    public String addmenu(AddmenuVo addmenuVo) {
        MsmtoolsMenuDo parentDo = authMapper.selectOneMsmtoolsMenuByMId(addmenuVo.getParent_m_id());
        if(Objects.nonNull(parentDo) && parentDo.getParentMId()!=0) return "不可创建三级菜单";

        MsmtoolsMenuDo msmtoolsMenuDo = new MsmtoolsMenuDo();

        List<String> list = Arrays.stream(addmenuVo.getPath().split("/")).collect(Collectors.toList());
        if(list.size()==2){
            msmtoolsMenuDo.setParentMId(addmenuVo.getParent_m_id());
            msmtoolsMenuDo.setPath("/"+list.get(1));
        } else return "创建失败,菜单路径格式: /xxxxx";

//        List<String> list = Arrays.stream(addmenuVo.getPath().split("/")).collect(Collectors.toList());
//        if(list.size()==3){
//            MsmtoolsMenuDo parentMsmtoolsMenuDo = authMapper.selectoneMsmtoolsMenuByPath("/"+list.get(1));
//            msmtoolsMenuDo.setParentMId(parentMsmtoolsMenuDo.getMId());
//            msmtoolsMenuDo.setPath("/"+list.get(2));
//        }else if(list.size()==2){
//            msmtoolsMenuDo.setParentMId(addmenuVo.getParent_m_id());
//            msmtoolsMenuDo.setPath("/"+list.get(1));
//        }else {
//            return "创建失败,菜单路径格式: /A/B";
//        }

        msmtoolsMenuDo.setIcon(addmenuVo.getIcon());
        msmtoolsMenuDo.setTitle(addmenuVo.getTitle());
        msmtoolsMenuDo.setOrders(addmenuVo.getOrder());
        msmtoolsMenuDo.setKeepAlive(addmenuVo.getKeep_alive());
        msmtoolsMenuDo.setShow("true");
        msmtoolsMenuDo.setDelFlag(0);

        int count = authMapper.addmenu(msmtoolsMenuDo);
        return count>0?"添加成功":"失败";
    }

    @Override
    public String updateMenu(UpdateMenuVo updateMenuVo) {
        MsmtoolsMenuDo msmtoolsMenuDo = authMapper.selectOneMsmtoolsMenuByMId(updateMenuVo.getM_id());
        if(Objects.isNull(msmtoolsMenuDo)) return "更新失败,请刷新重试";

        List<String> list = Arrays.stream(updateMenuVo.getPath().split("/")).collect(Collectors.toList());
        if(list.size()==2)
            msmtoolsMenuDo.setPath("/"+list.get(1));
        else
            return "创建失败,菜单路径格式: /xxxxx";

        msmtoolsMenuDo.setPath(updateMenuVo.getPath());
        msmtoolsMenuDo.setIcon(updateMenuVo.getIcon());
        msmtoolsMenuDo.setTitle(updateMenuVo.getTitle());
        msmtoolsMenuDo.setOrders(updateMenuVo.getOrder());
        msmtoolsMenuDo.setKeepAlive(updateMenuVo.getKeep_alive());
        msmtoolsMenuDo.setShow("true");
        msmtoolsMenuDo.setDelFlag(0);

        int count = authMapper.updateMenu(msmtoolsMenuDo);
        return count>0?"添加成功":"失败";
    }

    @Override
    public String deleteMenuByMId(UpdateMenuVo updateMenuVo) {
        int parent_m_id = updateMenuVo.getParent_m_id();
            if ((parent_m_id == 0)) {
                List<MsmtoolsMenuDo> msmtoolsMenuDos = authMapper.selectMsmtoolsMenuListByParentMId(updateMenuVo.getM_id());
                if (msmtoolsMenuDos.size() > 0) return "请先删除子菜单";
            }
        authMapper.deleteMenuByMId(updateMenuVo.getM_id());
        return "删除成功";
    }

    @Override
    public String editType(UpdatePowerVo updatePowerVo) {

        UpdatePowerDo powerDo = new UpdatePowerDo();
        powerDo.setMenu_id(getMenu_id(updatePowerVo));
        powerDo.setType_id(updatePowerVo.getType_id());
        powerDo.setName(updatePowerVo.getName());

        int count = authMapper.editType(powerDo);
        return count>0?"添加成功":"失败";
    }

    @Override
    public String addtype(UpdatePowerVo updatePowerVo) {
        UpdatePowerDo powerDo = new UpdatePowerDo();
        powerDo.setMenu_id(getMenu_id(updatePowerVo));
        powerDo.setName(updatePowerVo.getName());
        int count = authMapper.addtype(powerDo);
        return count>0?"添加成功":"失败";
    }

    private String getMenu_id(UpdatePowerVo updatePowerVo) {
        List<Integer> list = new ArrayList<>(updatePowerVo.getMenu_id());
        AtomicReference<String> reference = new AtomicReference<>("");
        list.forEach(integer -> reference.set(reference.get() + integer + ","));
        return reference.get().substring(0, reference.get().length() - 1);
    }

    private MsmtoolsMenuDto copyMsmtoolsDto(MsmtoolsMenuDo msmtoolsMenuDo) {
        MsmtoolsMenuDto msmtoolsMenuDto = new MsmtoolsMenuDto();
        msmtoolsMenuDto.setM_id(msmtoolsMenuDo.getMId());
        if (msmtoolsMenuDo.getParentMId() != 0)
            msmtoolsMenuDto.setParent_m_id(msmtoolsMenuDo.getParentMId());
        msmtoolsMenuDto.setPath(msmtoolsMenuDo.getPath());
        msmtoolsMenuDto.setShow(msmtoolsMenuDo.getShow());
        msmtoolsMenuDto.setTitle(msmtoolsMenuDo.getTitle());
        msmtoolsMenuDto.setIcon(msmtoolsMenuDo.getIcon());
        msmtoolsMenuDto.setOrders(msmtoolsMenuDo.getOrders());
        msmtoolsMenuDto.setKeep_alive(msmtoolsMenuDo.getKeepAlive());
        return msmtoolsMenuDto;
    }

    private MsmtoolsMenuAndChildrenDto copyMsmtoolsMenuAndChildrenDto(MsmtoolsMenuDo msmtoolsMenuDo) {
        MsmtoolsMenuAndChildrenDto msmtoolsMenuAndChildrenDto = new MsmtoolsMenuAndChildrenDto();
        msmtoolsMenuAndChildrenDto.setM_id(msmtoolsMenuDo.getMId());
        if (msmtoolsMenuDo.getParentMId() != 0)
            msmtoolsMenuAndChildrenDto.setParent_m_id(msmtoolsMenuDo.getParentMId());
        msmtoolsMenuAndChildrenDto.setPath(msmtoolsMenuDo.getPath());
        msmtoolsMenuAndChildrenDto.setShow(msmtoolsMenuDo.getShow());
        msmtoolsMenuAndChildrenDto.setTitle(msmtoolsMenuDo.getTitle());
        msmtoolsMenuAndChildrenDto.setIcon(msmtoolsMenuDo.getIcon());
        msmtoolsMenuAndChildrenDto.setOrders(msmtoolsMenuDo.getOrders());
        msmtoolsMenuAndChildrenDto.setKeep_alive(msmtoolsMenuDo.getKeepAlive());
        return msmtoolsMenuAndChildrenDto;
    }

    private String getPswd(String account,String pswd) {
        //MD5加密
        ByteSource credentialsSalt = ByteSource.Util.bytes(account);
        return new SimpleHash("MD5", pswd, credentialsSalt, 1).toString().toString();
    }

    @Override
    public String searchVehicleData(String vin) {

        return null;
    }

    @Override
    public BaseRestResponse<SearchVehicleDataAllDto> searchVehicleDataAll(String vin) {

        if(Objects.isNull(vin))
            return ResponseUtils.fail();

        BaseRestResponse<SearchVehicleDataAllDto> response = new BaseRestResponse<>();

        AtomicReference<String> statusCode = new AtomicReference<>("0") ;
        AtomicReference<String> statusMessage = new AtomicReference<>("查询成功");

        AtomicReference<String> simStatus_atmic = new AtomicReference<>();
        AtomicReference<VehicleWithSimResp> simByVin_atomic = new AtomicReference<>(new VehicleWithSimResp());
        AtomicReference<DeviceVehicle> deviceVehicle_atomic = new AtomicReference<>(new DeviceVehicle());
        AtomicReference<MsRemoteRelationVo> remoteRelationVo_atomic = new AtomicReference<>(new MsRemoteRelationVo());
        AtomicReference<VhlDataV2Vo> vhlDataV2Vo_atomic = new AtomicReference<>(new VhlDataV2Vo());
        AtomicReference<CreditConfigStatusResp> creditConfigStatusResp_atomic = new AtomicReference<>(new CreditConfigStatusResp());
        AtomicReference<List<UserProfileListItemVo>> userProfileList_atomic = new AtomicReference<>(new ArrayList<>());
        AtomicReference<List<BluekeyDetailVo>> bluekeyList_atomic = new AtomicReference<>(new ArrayList<>());
        AtomicReference<Map<String, Object>> hashMap_atomic = new AtomicReference<>(new HashMap<>());
        AtomicReference<PageResult<NewFeedbackRecord>> newFeedbackRecord_atomic = new AtomicReference<>();

        CompletableFuture<VehicleWithSimResp>          future1 = CompletableFuture.supplyAsync(() -> getVehicleWithSimResp(vin));
        CompletableFuture<MsRemoteRelationVo>          future2 = CompletableFuture.supplyAsync(() -> getMsRemoteRelationVo(vin));
        CompletableFuture<List<UserProfileListItemVo>> future3 = CompletableFuture.supplyAsync(() -> getUserProfileListItemVoList(vin));
        CompletableFuture<DeviceVehicle>               future4 = CompletableFuture.supplyAsync(() -> getDeviceVehicle(vin));
        CompletableFuture<VhlDataV2Vo>                 future5 = CompletableFuture.supplyAsync(() -> getVhlDataV2Vo(vin));
        CompletableFuture<CreditConfigStatusResp>      future6 = CompletableFuture.supplyAsync(() -> getCreditConfigStatusResp(vin));
        CompletableFuture<Void> allFutures = CompletableFuture.allOf(future1, future2, future3, future4, future5,future6);
        CompletableFuture<Void> action = allFutures.thenCompose(v -> {
            VehicleWithSimResp vehicleWithSimResp   = future1.join();
            MsRemoteRelationVo msRemoteRelationVo   = future2.join();
            List<UserProfileListItemVo> userVoList  = future3.join();
            DeviceVehicle deviceVehicle             = future4.join();
            VhlDataV2Vo vhlDataV2Vo                 = future5.join();
            CreditConfigStatusResp configStatusResp = future6.join();
            simByVin_atomic.set(vehicleWithSimResp);
            remoteRelationVo_atomic.set(msRemoteRelationVo);
            userProfileList_atomic.set(userVoList);
            deviceVehicle_atomic.set(deviceVehicle);
            vhlDataV2Vo_atomic.set(vhlDataV2Vo);
            creditConfigStatusResp_atomic.set(configStatusResp);
            List<BluekeyDetailVo> bluekeyDetailVos = bluekeyList_atomic.get();

            ArrayList<UserProfileListItemVo> owner_list = new ArrayList<>();
            ArrayList<UserProfileListItemVo> borrow_list = new ArrayList<>();
            userVoList.forEach(userProfileListItemVo -> {
                if (userProfileListItemVo.getRelationshipType()==1)
                    owner_list.add(userProfileListItemVo);
                else borrow_list.add(userProfileListItemVo);
            });

            CompletableFuture<Void> futureC = CompletableFuture.supplyAsync(() -> getUnicom(vin, hashMap_atomic, vehicleWithSimResp, msRemoteRelationVo));
            CompletableFuture<Void> futureD = CompletableFuture.supplyAsync(() -> getSimStatus(simStatus_atmic, vehicleWithSimResp, deviceVehicle));
            CompletableFuture<Void> futureE = CompletableFuture.supplyAsync(() -> bluekey(vin, bluekeyDetailVos, msRemoteRelationVo, userVoList, deviceVehicle, owner_list, owner_list, 1));
            CompletableFuture<Void> futureF = CompletableFuture.supplyAsync(() -> bluekey(vin, bluekeyDetailVos, msRemoteRelationVo, userVoList, deviceVehicle, owner_list, borrow_list, 0));
            CompletableFuture<Void> futureG = CompletableFuture.supplyAsync(() -> getSeriesName(deviceVehicle_atomic, deviceVehicle));
            CompletableFuture<Void> futureH = CompletableFuture.supplyAsync(() -> getFeedBack(vin, newFeedbackRecord_atomic, msRemoteRelationVo));
            CompletableFuture<Void> completableFuture = CompletableFuture.allOf(futureC, futureD, futureE, futureF ,futureG ,futureH);
            bluekeyList_atomic.set(bluekeyDetailVos);
            return completableFuture;
        });

        CompletableFuture<Void> timeoutFuture = new CompletableFuture<>();
        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
        scheduler.schedule(() -> {timeoutFuture.completeExceptionally(new TimeoutException());}, 5, TimeUnit.SECONDS);

        CompletableFuture<Void> result = action.applyToEither(timeoutFuture, Function.identity());         // 合并
        action.applyToEither(timeoutFuture, Function.identity()).join();
        result.exceptionally(e -> {
            if (e instanceof Exception) {
                 log.info("查询超时");
                statusCode.set("1");
                statusMessage.set("查询超时");
            }
            return null;
        });

        response.setStatusCode(statusCode.get());
        response.setStatusMessage(statusMessage.get());

        SearchVehicleDataAllDto dto = new SearchVehicleDataAllDto();
        dto.setUserProfileListItemVoList(userProfileList_atomic.get());
        dto.setMsRemoteRelationVo(remoteRelationVo_atomic.get());
        dto.setVehicleWithSimResp(simByVin_atomic.get());
        dto.setRsMap(hashMap_atomic.get());
        dto.setDeviceVehicle(deviceVehicle_atomic.get());
        dto.setSimStatus(simStatus_atmic.get());
        dto.setBluekeyDetailVoList(bluekeyList_atomic.get());
        dto.setVhlDataV2Vo(vhlDataV2Vo_atomic.get());
        dto.setPageResult(newFeedbackRecord_atomic.get());
        dto.setCreditConfigStatusResp(creditConfigStatusResp_atomic.get());

        response.setData(dto);
        return response;
    }



    private Void getFeedBack(String vin, AtomicReference<PageResult<NewFeedbackRecord>> newFeedbackRecord_atomic, MsRemoteRelationVo msRemoteRelationVo) {
        PageResult<NewFeedbackRecord> data = new PageResult<>();
        try {
            NewFeedbackPageVo feedbackRecord = new NewFeedbackPageVo();
            feedbackRecord.setVin(vin);
            feedbackRecord.setProjectId(msRemoteRelationVo.getProjectId());
            feedbackRecord.setPage(1);
            feedbackRecord.setSize(10);
            ResultData<PageResult<NewFeedbackRecord>> pageList = msinfofeedbackFeginClient.findPageList(feedbackRecord);
            data = pageList.getData();
            log.info("feedbackRecord::"+JSON.toJSONString(data));
        } catch (Exception e) {
            Thread.currentThread().interrupt();
        }
        newFeedbackRecord_atomic.set(data);
        return null;
    }

    private Void getSeriesName(AtomicReference<DeviceVehicle> deviceVehicle_atomic, DeviceVehicle deviceVehicle) {
        SeriesDetailResp data;
        try {
            BaseRestResponse<SeriesDetailResp> seriesByCode = msDeviceFeignClient.findSeriesByCode(deviceVehicle.getSeriesId());
            data = seriesByCode.getData();
            log.info("SeriesDetailResp::"+JSON.toJSONString(data));
            deviceVehicle.setSeriesName(data.getName());
        } catch (Exception e) {
            Thread.currentThread().interrupt();
        }
        deviceVehicle_atomic.set(deviceVehicle);
        return null;
    }

    private Void getSimStatus(AtomicReference<String> simStatus_atmic, VehicleWithSimResp vehicleWithSimResp, DeviceVehicle deviceVehicle) {
        String iccid = vehicleWithSimResp.getIccid();
        String seriesId = deviceVehicle.getSeriesId();

        StopWatch stopWatch = new StopWatch();
        stopWatch.start("查询车辆SIM状态");

        String simStatus = null;
        if (Objects.nonNull(seriesId)) {
            if (Arrays.asList(carName_old_dfpvivi).contains(seriesId)) {
                try {
                    simStatus = JasperUtils.getJasperSimStatus(iccid);
                } catch (IOException e) {
                    e.printStackTrace();
                }

            } else if (Arrays.asList(carName_new_dfpvivi).contains(seriesId)) {
                String app_id = "Ncrn2IQakZ";
                String app_secret = "e5Ue2eJ9VY9lu36I23axGh9k5n8Lt3";
                String openId = "36370ouDfQxEhhk";
                simStatus = JasperUtils.getSimStatus(app_id, app_secret, openId, iccid);

            } else if (Arrays.asList(carName_dnaivi).contains(seriesId)) {
                String app_id = "e5ASM4zk7g";
                String app_secret = "aBPmT6aAKX4rnHeBs6IVzuI6Qm5f5y";
                String openId = "37099ou8WdLeciq";
                simStatus = JasperUtils.getSimStatus(app_id, app_secret, openId, iccid);

            } else {
                Console.log("未指定的车型");
                simStatus = "未指定的车型";
            }

        } else  {
            simStatus = StrUtil.format("非联通车型", seriesId);
        }
        stopWatch.stop();
        simStatus_atmic.set(simStatus);
        return null;
    }

    private Void getUnicom(String vin, AtomicReference<Map<String, Object>> hashMap_atomic, VehicleWithSimResp vehicleWithSimResp, MsRemoteRelationVo msRemoteRelationVo) {
        String iccid = vehicleWithSimResp.getIccid();
        if(msRemoteRelationVo !=null && msRemoteRelationVo.getProjectId()!=null){
            QueryBalanceVo balanceVo = new QueryBalanceVo();
            balanceVo.setIccid(iccid);
            balanceVo.setRedisFlag(false);
            balanceVo.setVin(vin);

            String projectId = msRemoteRelationVo.getProjectId();
            if(Objects.equals(projectId,"dnaivi")){
                FlowDto flowDto = new FlowDto();
                flowDto.setIccid(iccid);
                UNicomDataResult UNicomDataResult = msunicomFeign.flowQuery(flowDto);
                log.info("dataResult::"+JSON.toJSONString(UNicomDataResult));
                if (UNicomDataResult != null  && UNicomDataResult.getStatusCode().equals("0")) {
                    Map<String, Object> map = calFlowUnicom_dnaivi(UNicomDataResult);
                    hashMap_atomic.set(map);
                }

            }else if (Objects.equals(projectId,"dfpvivi")){
                BaseRestResponse<BalanceUsedResponse> mnoResult = msunicomFeign.queryBalanceV1(projectId, balanceVo);
                log.info("mnoResult::"+JSON.toJSONString(mnoResult));
                if (mnoResult != null  && mnoResult.getStatusCode().equals("0")) {
                    BalanceUsedResponse resultData = mnoResult.getData();
                    JSONObject dataJSON = (JSONObject) JSON.toJSON(resultData);
                    Map<String, Object> map = calFlowByUnicom(dataJSON);

                    BalanceBody body = resultData.getBody();
                    if(Objects.nonNull(body))
                        map.put("detail",body.getDetail());
                    hashMap_atomic.set(map);
                }
            }

        }
        return null;
    }

    private VhlDataV2Vo getVhlDataV2Vo(String vin) {
        VhlDataV2Vo data = null;
        try {
            BaseRestResponse<VhlDataV2Vo> vhlDataV2VoRep = msvehiclestatusFeign.getX37StatusV3(vin);
            data = vhlDataV2VoRep.getData();
            log.info("VhlDataV2Vo::"+JSON.toJSONString(data));
        } catch (Exception e) {
            Thread.currentThread().interrupt();
        }
        return data;
    }

    private DeviceVehicle getDeviceVehicle(String vin) {
        DeviceVehicle data = null;
        try {
            data = msDeviceFeignClient.getDeviceVehicle(vin);
            log.info("DeviceVehicle::"+JSON.toJSONString(data));

            data.setEnrollStatusName(EnrollStatusEnum.getDescByCode(data.getEnrollStatus()));
            data.setVehicleTypeName(VehicleTypeEnum.getDescByCode(data.getVhlType()));
            data.setRealNameStatusName(RealNameStatusEnum.getDescByCode(Integer.parseInt(data.getRealNameStatus())));
            data.setCarSptName(CarsptEnum.getDescByCode(data.getCarSpt()));

        } catch (Exception e) {
            Thread.currentThread().interrupt();
        }
        return data;
    }

    private List<UserProfileListItemVo> getUserProfileListItemVoList(String vin) {
        List<UserProfileListItemVo> dataList = new ArrayList<>();
        try {
            BaseRestResponse<List<UserProfileListItemVo>> bindUserInfoByDevice = msAccountFeignClient.getAllBindUserInfoByDevice(vin);
            log.info("List<UserProfileListItemVo>::"+JSON.toJSONString(bindUserInfoByDevice));
            if(Objects.nonNull(bindUserInfoByDevice.getData()))
                dataList = bindUserInfoByDevice.getData();
        } catch (Exception e) {
            Thread.currentThread().interrupt();
        }
        return dataList;
    }

    private MsRemoteRelationVo getMsRemoteRelationVo(String vin) {
        MsRemoteRelationVo data = null;
        try {
            BaseRestResponse<MsRemoteRelationVo> remoteRelation = msdmsFeign.findRemoteRelation(vin, false);
            log.info(JSON.toJSONString(remoteRelation));
            data = remoteRelation.getData();
        } catch (Exception e) {
            Thread.currentThread().interrupt();
        }
        return data;
    }

    private VehicleWithSimResp getVehicleWithSimResp(String vin) {
        VehicleWithSimResp data = null;
        try {
            BaseRestResponse<VehicleWithSimResp> feginData = msDeviceFeignClient.findVehicleWithSimByVin(vin);
            data = feginData.getData();
            log.info("VehicleWithSimResp::"+JSON.toJSONString(data));
        } catch (Exception e) {
            Thread.currentThread().interrupt();
        }
        return data;
    }

    private Void bluekey(String vin, List<BluekeyDetailVo> bluekeyDetailVoList, MsRemoteRelationVo msRemoteRelationVo, List<UserProfileListItemVo> userVoList, DeviceVehicle deviceVehicle, ArrayList<UserProfileListItemVo> owner_list, List<UserProfileListItemVo> user_list, int number) {
        try {
            //蓝牙供应商 0：无； 1：自研； 2：银基有感蓝牙钥匙； 3：银基无感蓝牙钥匙； 4：自研2.0； 5：车联网蓝牙钥匙
            if(Objects.isNull(msRemoteRelationVo)) return null;
            if(Objects.isNull(deviceVehicle)) return null;

            String projectId = msRemoteRelationVo.getProjectId();
            String bluetoothProvider = msRemoteRelationVo.getBluetoothProvider();
            Integer carSpt = deviceVehicle.getCarSpt();
            if(Objects.nonNull(carSpt) && carSpt==1) bluetoothProvider = "5";

            if(userVoList.size() == 0) return null;

            UserProfileListItemVo user = new UserProfileListItemVo();
            if(user_list.size()>0) user = user_list.get(0);

            if(Objects.isNull(bluetoothProvider)) return null;
            switch (bluetoothProvider){
                case "1": if (getSoBluekey(projectId, bluekeyDetailVoList, user)) return null;  break;
                case "2": break;
                case "5":
                {
                    UserProfileListItemVo owner = owner_list.get(0);
                    if (getBluekey(vin, owner.getUserAccountSid(), owner.getUserAccountBindId(), projectId, bluekeyDetailVoList, number)) return null;  break;
                }
            }
            log.info("bluekeyDetailVoList::"+JSON.toJSONString(bluekeyDetailVoList));
            return null;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    private boolean getBluekey(String vin,Long userAccountSid, String userAccountBindId, String projectId, List<BluekeyDetailVo> bluekeyDetailVoList, int number) {


        HashMap<String, Object> map = new HashMap<>();
        map.put("X-pateo-project", projectId);
        BaseRestResponse<List<D53DeviceBluetoothKeyListResp>> listBaseRestResponse = msIBlueToothKeyFeignClient.searchOwnerKeys(map, userAccountSid, userAccountBindId, vin);
        log.info("msIBlueToothKey::searchOwnerKeys::"+JSON.toJSONString(listBaseRestResponse.getData()));
        if(listBaseRestResponse.getData()==null) return true;

        List<D53DeviceBluetoothKeyListResp> list = listBaseRestResponse.getData();
        if(list.size()>0){
            D53DeviceBluetoothKeyListResp listResp = list.get(0);
            listResp.getBluetoothKeys().forEach(d53ApplyResp -> {
                if(d53ApplyResp.getRelationship()== number){
                    BluekeyDetailVo bluekeyDetailVo = new BluekeyDetailVo();
                    bluekeyDetailVo.setId(d53ApplyResp.getId());
                    bluekeyDetailVo.setDeviceId(d53ApplyResp.getDeviceId());
                    bluekeyDetailVo.setKeyStatus(d53ApplyResp.getKeyStatus());
                    bluekeyDetailVo.setEndTime(d53ApplyResp.getBluetoothSensitiveInfo().getKeyExpireTime());
                    bluekeyDetailVo.setReationship(d53ApplyResp.getRelationship());
                    bluekeyDetailVo.setUpdatetime(d53ApplyResp.getCreateTime());
                    bluekeyDetailVo.setUserAccountSid(d53ApplyResp.getUserAccountSid());
                    bluekeyDetailVo.setParkingKeyExpireTime(null);
                    BeanUtils.copyProperties(d53ApplyResp,bluekeyDetailVo);
                    bluekeyDetailVoList.add(bluekeyDetailVo);
                }
            });
        }
        return false;
    }

    private boolean getSoBluekey(String projectId, List<BluekeyDetailVo> bluekeyDetailVoList, UserProfileListItemVo user) {
        HashMap<String, String> map = new HashMap<>();
        map.put("X-pateo-origin-projectid", projectId);
        map.put("X-pateo-session",JSON.toJSONString(new HeaderSession(user.getUserAccountSid(), user.getUserAccountBindId(), user.getMobilePhone())));
        BaseRestResponse<Map<String, Object>> restResponse = msSoIBlueToothKeyFeignClient.searchBleutoothKey(map, new SoMobileDeviceNo(user.getMobilePhone()));
        log.info("msSoIBlueToothKey::searchBleutoothKey::"+JSON.toJSONString(restResponse));
        Map<String, Object> bluekey_map = restResponse.getData();
        if(bluekey_map ==null && bluekey_map.size()==0) return true;

        String user_list;
        if(user.getRelationshipType() ==1)
            user_list = "ownerList";
        else if(user.getRelationshipType() ==0)
            user_list = "borrowList";
        else return true;

        List listTemp = (List) bluekey_map.get(user_list);
        SoBluetoothKeyWithDevice user_key = objectMapToBean(listTemp.get(0), SoBluetoothKeyWithDevice.class);

        BluekeyDetailVo bluekeyDetailVo = new BluekeyDetailVo();
        bluekeyDetailVo.setId(user_key.getId());
        bluekeyDetailVo.setDeviceId(user_key.getDeviceId());
        bluekeyDetailVo.setKeyStatus(user_key.getKeyStatus());
        bluekeyDetailVo.setEndTime(user_key.getKeyExpireTime());
        bluekeyDetailVo.setReationship(user_key.getRelationship());
        bluekeyDetailVo.setUpdatetime(user_key.getUpdatetime().toString());
        bluekeyDetailVo.setUserAccountSid(user_key.getUserAccountSid());
        bluekeyDetailVo.setParkingKeyExpireTime(null);
        BeanUtils.copyProperties(user_key,bluekeyDetailVo);
        bluekeyDetailVoList.add(bluekeyDetailVo);
        return false;
    }

    private <T> T objectMapToBean(Object o, Class<T> classZ) {
        return JSON.parseObject(JSON.toJSONString(o), classZ);
    }

    private Map<String, Object> calFlowUnicom_dnaivi(UNicomDataResult UNicomDataResult) {
        ArrayList<PackageVo> list = new ArrayList<>();
        List<HashMap> voList = castList(UNicomDataResult.getData(), HashMap.class);
        voList.forEach(hashMap -> list.add(BeanUtil.fillBeanWithMap(hashMap, new PackageVo(), false)));

        // 已使用
        // 剩余流量
        AtomicReference<Double> monthBalanceFlow_atomic = new AtomicReference<>(0.00D);
        AtomicReference<Double> monthUsedFlow_atomic = new AtomicReference<>(0.00D);
        list.forEach(packageVo -> {
            monthBalanceFlow_atomic.set(monthBalanceFlow_atomic.get()+packageVo.getPeriodTotalData().doubleValue());
            monthUsedFlow_atomic.set(monthUsedFlow_atomic.get()+packageVo.getPeriodDataUsed().doubleValue());
        });

        Map<String, Object> rsMap = new HashMap<>();
        rsMap.put("monthUsedFlow", new BigDecimal(monthUsedFlow_atomic.get() / 1024).setScale(3, BigDecimal.ROUND_DOWN).toString());
        rsMap.put("monthBalanceFlow", new BigDecimal(monthBalanceFlow_atomic.get() / 1024).setScale(3, BigDecimal.ROUND_DOWN).toString());
        rsMap.put("detail",voList);
        return rsMap;
    }

    /**
     * 计算unicom流量使用情况
     * @param dataJSON
     * @return
     */
    private Map<String, Object> calFlowByUnicom(JSONObject dataJSON) {

        // 流量限额
        double quota = 0.00D;
        // 已使用
        double monthUsedFlow = 0.00D;
        // 剩余流量
        double monthBalanceFlow = 0.00D;

        JSONObject unicomJSON = dataJSON.getJSONObject("body");
        JSONArray summaryArray = unicomJSON.getJSONArray("summary");
        for (Object temp : summaryArray) {
            JSONObject summary = (JSONObject) temp;
            if (summary.containsKey("packageGroup") && summary.getString("packageGroup").equals("BASIC")) {

                double basicQuota = summary.getBigDecimal("trafficQuota").doubleValue();
                double basicUsage = summary.getBigDecimal("trafficUsage").doubleValue();
                quota += basicQuota;
                monthUsedFlow += basicUsage;
            }
            if (summary.containsKey("packageGroup") && summary.getString("packageGroup").equals("ADDITIONAL")) {
                double addQuota = summary.getBigDecimal("trafficQuota").doubleValue();
                double addUsage = summary.getBigDecimal("trafficUsage").doubleValue();
                quota += addQuota;
                monthUsedFlow += addUsage;
            }
        }
        // 剩余流量
        monthBalanceFlow = (quota - monthUsedFlow);
        Map<String, Object> rsMap = new HashMap<>();
        rsMap.put("monthUsedFlow", new BigDecimal(monthUsedFlow / 1024).setScale(3, BigDecimal.ROUND_DOWN).toString());
        rsMap.put("monthBalanceFlow", new BigDecimal(monthBalanceFlow / 1024).setScale(3, BigDecimal.ROUND_DOWN).toString());
        return rsMap;
    }

    // object转换list方法
    public static <T> List<T> castList(Object obj, Class<T> clazz) {
        List<T> result = new ArrayList<>();
        if (obj instanceof List) {
            for (Object o : (List<?>) obj) {
                if (clazz.isInstance(o)) {
                    result.add(clazz.cast(o));
                }
            }
        }
        return result;
    }


//---------------------------------------------------------------------------------------------------------
    @Override
    public BaseRestResponse<PageResult<NewFeedbackRecord>> getFeedBacklog(GetFeedbackVo getFeedbackVo) {
        PageResult<NewFeedbackRecord> data = new PageResult<>();
        try {
            if(getFeedbackVo.getVin()==null) return ResponseUtils.fail();
            BaseRestResponse<MsRemoteRelationVo> remoteRelation = msdmsFeign.findRemoteRelation(getFeedbackVo.getVin(), false);
            if( remoteRelation.getData() ==null && remoteRelation.getData().getProjectId()==null ) return ResponseUtils.fail();

            NewFeedbackPageVo feedbackRecord = new NewFeedbackPageVo();
            feedbackRecord.setVin(getFeedbackVo.getVin());
            feedbackRecord.setProjectId(remoteRelation.getData().getProjectId());
            feedbackRecord.setPage(1);
            feedbackRecord.setSize(10);
            ResultData<PageResult<NewFeedbackRecord>> pageList = msinfofeedbackFeginClient.findPageList(feedbackRecord);
            data = pageList.getData();
            data.getList().forEach(newFeedbackRecord -> {
                if (newFeedbackRecord.getImages()!=null)
                    newFeedbackRecord.setImages(JSON.parseObject(newFeedbackRecord.getImages(), new TypeReference<Map<String, String>>(){}).get("fileUri"));
            });

            data.setMapKey(getMsmtoolsColumnsDtos(vehicle_log));

            log.info("PageResult<NewFeedbackRecord>::"+JSON.toJSONString(data));
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseUtils.fail();
        }

        BaseRestResponse<PageResult<NewFeedbackRecord>> response = new BaseRestResponse<>();
        response.setStatusCode(ResponseEnum.SUCCESS.getCode());
        response.setStatusMessage(ResponseEnum.SUCCESS.getMsg());
        response.setData(data);
        return response;
    }

    private List<MsmtoolsColumnsDto> getMsmtoolsColumnsDtos(String tableName) {
        return authMapper.selectFieldListByBusiness(tableName).stream()
                .map(msmtoolsColumnsDo -> new MsmtoolsColumnsDto(
                        msmtoolsColumnsDo.getDataIndex(),
                        msmtoolsColumnsDo.getKey(),
                        msmtoolsColumnsDo.getTitle(),
                        Boolean.parseBoolean(msmtoolsColumnsDo.getHidden()))).collect(Collectors.toList());
    }


    public BaseRestResponse<CreditConfigStatusResp> getCreditBusinessVehicle(String vin) {
        try {
            return ResponseUtils.success(getCreditConfigStatusResp(vin));
        } catch (Exception e) {
            log.error("creditBusiness BaseService.getCreditBusinessVehicle error: e={}", e);
            return null;
        }

    }


    private CreditConfigStatusResp getCreditConfigStatusResp(String vin) {
        CreditConfigStatusResp creditConfigStatusResp = new CreditConfigStatusResp();
        MsCreditBusinessVehicle creditBusinessVehicle = msDeviceMapper.getMsCreditBusinessVehicleByVin(vin);
        // 新金融授信车状态判断
        if (Objects.nonNull(creditBusinessVehicle)) {
            if (Objects.equals(creditBusinessVehicle.getLockStatus(), Constants.DEFAULT_YES)) {
                // 锁车配置状态
                creditConfigStatusResp = new CreditConfigStatusResp()
                        .setVin(vin)
                        .setConfigStatus(VehicleStatusEnum.LOCK.getType())
                        .setConfigTime(creditBusinessVehicle.getLockDate())
                        .setIsCred("1");

            }else if (Objects.equals(creditBusinessVehicle.getLimpStatus(), Constants.DEFAULT_YES)) {
                // 跛行配置状态
                 creditConfigStatusResp = new CreditConfigStatusResp()
                         .setVin(vin)
                        .setConfigStatus(VehicleStatusEnum.LIMP.getType())
                        .setConfigTime(creditBusinessVehicle.getLimpDate())
                         .setIsCred("1");
            }else {
                // 正常状态
                creditConfigStatusResp = new CreditConfigStatusResp()
                        .setVin(vin)
                        .setConfigStatus(VehicleStatusEnum.NORMAL.getType())
                        .setIsCred("1");
            }

        } else {

            // 老金融授信车状态判断
            BaseDeviceCreditCompanyCar creditCompanyCar = msDeviceMapper.getBaseDeviceCreditCompanyCarByVin(vin);
            if (Objects.nonNull(creditCompanyCar)) {
                // 查询最新的锁车、跛行操作记录
                BaseDeviceCreditLockRecord record = msDeviceMapper.getBaseDeviceCreditLockRecordByVin(vin);
                Date configTime = Objects.isNull(record)? null:record.getOperationTime();
                // 锁车配置状态
                if (Objects.equals(creditCompanyCar.getCreditStatus(), Constants.DEFAULT_YES)) {
                    creditConfigStatusResp = new CreditConfigStatusResp()
                            .setVin(vin)
                            .setConfigStatus(VehicleStatusEnum.LOCK.getType())
                            .setConfigTime(configTime).setIsCred("1");
                }else
                // 跛行配置状态
                if (Objects.equals(creditCompanyCar.getLimpStatus(), Constants.DEFAULT_YES)) {
                    creditConfigStatusResp = new CreditConfigStatusResp()
                            .setVin(vin)
                            .setConfigStatus(VehicleStatusEnum.LIMP.getType())
                            .setConfigTime(configTime).setIsCred("1");
                }else{
                    // 正常状态
                    creditConfigStatusResp = new CreditConfigStatusResp()
                            .setVin(vin)
                            .setConfigStatus(VehicleStatusEnum.NORMAL.getType()).setIsCred("1");
                }

            }else{
                creditConfigStatusResp = new CreditConfigStatusResp().setVin(vin).setIsCred("0");
            }
        }
        log.info("creditConfigStatusResp::"+JSON.toJSONString(creditConfigStatusResp));
        return creditConfigStatusResp;
    }


    @Override
    public BaseRestResponse<List<AddDataByMonthDto>> getAddDataByMonth(String startMonth, String endMonth) {
        List<AddDataByMonthDto> data = tspReportMapper.getAddDataByMonth(startMonth, endMonth);
        return ResponseUtils.success(data);
    }

    @Override
    public BaseRestResponse<AddDataByMonthAndVersionDto> getAddDataByMonthAndVersion(AddDataByMonthAndVersionVo addDataByMonthAndVersionVo) {
        String startMonth = addDataByMonthAndVersionVo.getStartMonth();
        String endMonth = addDataByMonthAndVersionVo.getEndMonth();
        String vin = addDataByMonthAndVersionVo.getVin();
        List<String> versionList = addDataByMonthAndVersionVo.getVersionList();

        int page = addDataByMonthAndVersionVo.getPage();
        int pagesize = addDataByMonthAndVersionVo.getPagesize();

        if(page==0)     page=1;
        if(pagesize==0) pagesize=10;

        log.info("getAddDataByMonthAndVersion::" + "startMonth::"+startMonth + ",endMonth::"+endMonth + ",versionList::"+JSON.toJSONString(versionList));
        List<BaseAccountStaticExcelVo> baseAccountStaticList = tspReportMapper.getAddDataByMonthAndVersion(vin, startMonth, endMonth, versionList, (page - 1) * pagesize, pagesize);

        AddDataByMonthAndVersionDto data = new AddDataByMonthAndVersionDto();
        int total = tspReportMapper.getAddDataByMonthAndVersionCount(vin, startMonth, endMonth, versionList);
        data.setTotal(total);
        data.setMapKey(getMsmtoolsColumnsDtos(vehicle_statistics));
        data.setList(baseAccountStaticList);

        return ResponseUtils.success(data);
    }



    public void exportAddDataByMonthAndVersion(ExportDataByMonthAndVersionVo exportDataByMonthAndVersionVo, HttpServletResponse response) {
        try {
            String tableName = exportDataByMonthAndVersionVo.getExportName();
            if(tableName==null) return;

            String startMonth = exportDataByMonthAndVersionVo.getStartMonthExport();
            String endMonth = exportDataByMonthAndVersionVo.getEndMonthExport();
            String vin = exportDataByMonthAndVersionVo.getVin();
            List<String> versionList = exportDataByMonthAndVersionVo.getVersionListExport();

            log.info("exportAddDataByMonthAndVersion::" + "startMonth::"+startMonth + ",endMonth::"+endMonth + ",versionList::"+JSON.toJSONString(versionList));
            List<BaseAccountStaticExcelVo> baseAccountStaticExcelVoList = tspReportMapper.exportAddDataByMonthAndVersion(vin, startMonth, endMonth, versionList);
            ExcelUtils.export(tableName,"sheet1", baseAccountStaticExcelVoList, BaseAccountStaticExcelVo.class, response);

        } catch (Exception e) {
            e.printStackTrace();
            log.info("downLoadExcel() 出现异常");
        }
    }

    public void exportAddDataByMonthAndVersionV2(ExportDataByMonthAndVersionVo exportDataByMonthAndVersionVo, HttpServletResponse response) {
        try {
            //保有量统计
            String startMonth ="2023-05";
            String endMonth = exportDataByMonthAndVersionVo.getMonthExport();
            List<String> versionList = exportDataByMonthAndVersionVo.getVersionListExport();
            String tableName = exportDataByMonthAndVersionVo.getExportName();
            String sheet1Export = exportDataByMonthAndVersionVo.getSheet1Export();
            String sheet2Export = exportDataByMonthAndVersionVo.getSheet2Export();

            if(tableName==null || endMonth==null || versionList.size()==0 || sheet1Export==null || sheet2Export==null) return;
            List<String> result = getMonthsBefore(endMonth);
            log.info("exportAddDataByMonthAndVersion::"
                    + "tableName::"+tableName
                    + "sheet1Export::"+sheet1Export
                    + "sheet2Export::"+sheet2Export
                    + "startMonth::"+startMonth
                    + ",endMonth::"+endMonth
                    + ",versionList::" +JSON.toJSONString(versionList));

           List<BaseAccountStaticExcelVo> baseAccountStaticExcelVoList = tspReportMapper.exportAddDataByMonthAndVersion(null, startMonth, endMonth, versionList);
           List<BaseAccountStaticExcelVo> staticExcelVoList = baseAccountStaticExcelVoList.stream().filter(vo -> result.contains(vo.getStaticMonth())).collect(Collectors.toList());

            exportDouble(tableName,
                    sheet1Export,
                    sheet2Export,
                    baseAccountStaticExcelVoList,
                    staticExcelVoList,
                    BaseAccountStaticExcelVo.class,
                    response);

        } catch (Exception e) {
            e.printStackTrace();
            log.info("downLoadExcel() 出现异常");
        }
    }

     String  split ="-";
     String pattern = "%02d";
    public  List<String> getMonthsBefore(String inputDate) {
        String year = inputDate.split(split)[0];
        String month = inputDate.split(split)[1];

        List<String> months = new ArrayList<>();
        for (int i = 1; i < Integer.parseInt(month)+1; i++) {
            if (i < 10)
                months.add(year + "-" + String.format(pattern, i));
             else
                months.add(year + "-" + i);
        }
        return months;
    }

    public static <T> void exportDouble(
            String tableName,
            String sheetName1,
            String sheetName2,
            List<T> data1,
            List<T> data2,
            Class<T> tClass,
            HttpServletResponse response) {
        try (ServletOutputStream outputStream = response.getOutputStream()) {
            String fileName = String.format("%s.xlsx", tableName);
            response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
            response.setContentType("application/vnd.ms-excel;charset=utf-8");
            response.setCharacterEncoding("utf-8");

            ExcelWriter excelWriter = EasyExcel.write(outputStream, tClass)
                    .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                    .build();

            WriteSheet writeSheet1 = EasyExcel.writerSheet(sheetName1).build();
            excelWriter.write(data1, writeSheet1);

            WriteSheet writeSheet2 = EasyExcel.writerSheet(sheetName2).build();
            excelWriter.write(data2, writeSheet2);

            excelWriter.finish();
        } catch (Exception e) {
            log.error("{}导出异常", tableName, e);
        }
    }
}
